#include "Mesh.h"
#include "Resource.h"
#include "ResourcePool.h"


namespace Display
{
	Mesh::Mesh(ResourcePool * pool) : Display::DeviceUserBase() , Resource(pool)
	{
		vertexBuffer = nullptr;
		indexBuffer = nullptr;
	}


	Mesh::~Mesh(void)
	{
		Dispose();
	}

	void Mesh::Dispose()
	{
		
		if(vertexBuffer != nullptr)
		{
			vertexBuffer->Release();
			vertexBuffer = nullptr;
		}

		if(indexBuffer != nullptr)
		{
			indexBuffer->Release();
			indexBuffer = nullptr;
		}
	}

	void Mesh::DrawIndexed()
	{
		Bind();
		ID3D11DeviceContext * context = GetContext();

		context->DrawIndexed(indeciesInfo.count,0,0);

		context = nullptr;
	}

	void Mesh::Draw()
	{
		Bind();

		ID3D11DeviceContext * context = GetContext();

		context->Draw(vertsInfo.count,0);
		context = nullptr;
	}

	void Mesh::Bind()
	{
		ID3D11DeviceContext * context = GetContext();
	
		context->IASetVertexBuffers(0,1,&vertexBuffer,&vertsInfo.stride,&vertsInfo.offset);
		context->IASetIndexBuffer(indexBuffer,DXGI_FORMAT_R32_UINT,indeciesInfo.offset);

		context = nullptr;
	}

	Mesh * Mesh::Create(ID3D11Device * device,ResourcePool * pool)
	{
		Mesh * mesh = new Mesh(pool);
		mesh->SetDevice(device);


		return mesh;
	}

	D3D11_BUFFER_DESC  Mesh::GetBufferDesc(UINT size,BufferUsage usage,BufferType type)
	{
		D3D11_BUFFER_DESC desc;
		ZeroMemory(&desc,sizeof(D3D11_BUFFER_DESC));

		if(usage == STATIC)
			desc.Usage = D3D11_USAGE_DEFAULT;
		else 
			desc.Usage = D3D11_USAGE_DYNAMIC;

		desc.CPUAccessFlags = 0;
		desc.MiscFlags = 0;
		desc.ByteWidth = size;
		if(type == VERTEX)
			desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		else 
			desc.BindFlags = D3D11_BIND_INDEX_BUFFER;

		return desc;
	}

	void Mesh::AllocateVertexBuffer(UINT size,BufferUsage usage)
	{
		vertsInfo.size = size;
		D3D11_BUFFER_DESC desc = GetBufferDesc(size,usage,VERTEX);

		ID3D11Device * device = GetDevice();

		device->CreateBuffer(&desc,nullptr,&vertexBuffer);

		device = nullptr;
	}

	void Mesh::AllocateIndexBuffer(UINT size,BufferUsage usage)
	{
		indeciesInfo.size = size;
		D3D11_BUFFER_DESC desc = GetBufferDesc(size,usage,INDEX);

		ID3D11Device * device = GetDevice();

		device->CreateBuffer(&desc,nullptr,&indexBuffer);

		device = nullptr;
	}

	void  Mesh::AllocateAndFillVertexBuffer(UINT size,UINT stride,UINT count,UINT offset,BufferUsage usage,void * data)
	{
		vertsInfo.size = size;
		vertsInfo.count = count;
		vertsInfo.stride = stride;
		vertsInfo.offset = offset;

		D3D11_BUFFER_DESC desc = GetBufferDesc(size,usage,VERTEX);

		D3D11_SUBRESOURCE_DATA vertData;
		ZeroMemory(&vertData,sizeof(D3D11_SUBRESOURCE_DATA));

		vertData.pSysMem = data;

		ID3D11Device * device = GetDevice();

		device->CreateBuffer(&desc,&vertData,&vertexBuffer);

		device = nullptr;
	}

	void  Mesh::AllocateAndFillIndexBuffer(UINT size,UINT count,UINT offset,BufferUsage usage,void * data)
	{
		indeciesInfo.count = count;
		indeciesInfo.size = size;
		indeciesInfo.offset = offset;

		D3D11_BUFFER_DESC desc = GetBufferDesc(size,usage,INDEX);

		D3D11_SUBRESOURCE_DATA vertData;
		ZeroMemory(&vertData,sizeof(D3D11_SUBRESOURCE_DATA));

		vertData.pSysMem = data;

		ID3D11Device * device = GetDevice();

		device->CreateBuffer(&desc,&vertData,&indexBuffer);

		device = nullptr;
	}

	void Mesh::FillVertexBuffer(UINT stride,UINT count,UINT offset,void * data)
	{
		vertsInfo.stride = stride;
		vertsInfo.offset = offset;
		vertsInfo.count = count;

		ID3D11DeviceContext * context = GetContext();

		context->UpdateSubresource(vertexBuffer,0,nullptr,data,vertsInfo.stride,1);
		context = nullptr;
	}
	void Mesh::FillIndexBuffer(UINT count,UINT offset,void * data)
	{
		indeciesInfo.count = count;
		indeciesInfo.offset = offset;
		
		ID3D11DeviceContext * context = GetContext();

		context->UpdateSubresource(indexBuffer,0,nullptr,data,sizeof(UINT),1);
		context = nullptr;
	}

	void Mesh::OnZeroRefReach()
	{
		pool->DeAllocateMesh(this);
	}

}
